package br.com.ac.fatureweb.utilitary.validator;

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;


@FacesValidator("br.com.ac.fatureweb.utilitary.validator.CPFValidator")
public class CPFValidator implements Validator
{
	private static final String ERROR_MESSAGE = "CPF inválido.";

	@Override
	public void validate(final FacesContext context,
			final UIComponent toValidate, final Object value)
			throws ValidatorException {
		
		final String cpf = (String) value;

		if ( cpf == null )
			return;

		if ( !isValido(cpf) ) {
			throw new ValidatorException(new FacesMessage(
					FacesMessage.SEVERITY_ERROR, ERROR_MESSAGE, null));
		}
	}
	
	private boolean isValido(final String cpf)
	{
		if ( cpf != null && cpf.trim().length() > 0 && cpf.trim().length() <= 11 )
		{
			return cpf.substring(9, 11).equals(getCpfDigitoVerificador(cpf));
		}

		if ( cpf != null && cpf.trim().length() > 11 )
		{
			return Boolean.FALSE;
		}

		return Boolean.TRUE;
	}
	
	private String getCpfDigitoVerificador(final String cpf)	{

		boolean digitosIguais = true;

		try
		{
			// 1. Tratamento para todos os digitos repetidos
			for (int i = 0; i < cpf.length() - 1; i++)
			{
				if ( cpf.charAt(i) != cpf.charAt(i + 1) )
				{
					if ( cpf.charAt(i) != cpf.charAt(i + 1) )
					{
						digitosIguais = false;
						break;
					}
				}
			}

			// 1.1 Todos os digitos estão com o mesmo valor.
			if ( digitosIguais )
			{
				// Digito veficador invalido. Sera retorno false;
				return "0";
			}

			// 2. Obtem os valores para calculo do primeiro digito verificador
			int factor = 10, total = 0, subtotal = 0;
			for (int i = 0; i < 9; i++)
			{
				final int digit = Integer.parseInt(cpf.substring(i, i + 1));
				subtotal = digit * factor;
				total += subtotal;
				factor--;
			}

			// 2.1. Obtem o valor do primeiro digito verificador = 11 - last digit
			int primeirdoDigitoVerificador = 11 - total % 11;
			if ( primeirdoDigitoVerificador >= 10 )
			{
				primeirdoDigitoVerificador = 0;
			}

			// 3. Obtem os valores para calculo do segundo digito verificador
			factor = 11;
			total = 0;
			for (int i = 0; i < 10; i++)
			{
				final int digito = Integer.parseInt(cpf.substring(i, i + 1));
				if ( i == 9 )
				{
					subtotal = primeirdoDigitoVerificador * factor;
				}
				else
				{
					subtotal = digito * factor;
				}
				total += subtotal;
				factor--;
			}

			// 3.1. Obtem o valor do segundo digito verificador = 11 - last digit
			int segundoDigitoVerificador = 11 - total % 11;
			if ( segundoDigitoVerificador >= 10 )
			{
				segundoDigitoVerificador = 0;
			}

			// 4. Retorna o digito verificador
			return new String(new char[] { (char) ('0' + primeirdoDigitoVerificador),
					(char) ('0' + segundoDigitoVerificador) });
		}
		catch (final Exception e)
		{
			// Digito veficador invalido. Sera retorno false;
			return "0";
		}
	}
}